<template>
  <div class="min-h-screen py-8 px-4 sm:px-6 lg:px-8">
    <div class="max-w-4xl mx-auto">
      <!-- 页面标题 -->
      <div class="text-center mb-12">
        <h1 class="text-4xl font-bold mb-4 tech-text">HID 协议 API</h1>
        <p class="text-gray-300 text-lg">
          通过 WebHID API 与人机接口设备（如游戏手柄、键盘、鼠标等）进行通信
        </p>
      </div>

      <!-- 浏览器支持提示 -->
      <div v-if="!isSupported" class="tech-card mb-8 border-yellow-600">
        <div class="flex items-center mb-4">
          <i class="i-carbon-warning text-yellow-500 text-xl mr-3"></i>
          <h3 class="text-xl font-semibold text-yellow-500">浏览器支持提示</h3>
        </div>
        <p class="text-gray-300 mb-4">
          您的浏览器不支持 WebHID API。此功能需要 Chrome 89+ 或其他基于 Chromium 的浏览器。
        </p>
        <p class="text-gray-400 text-sm">
          注意：WebHID API 需要在安全上下文（HTTPS）中使用，且需要用户手势触发。
        </p>
      </div>

      <!-- 设备连接区域 -->
      <div class="tech-card mb-8">
        <h2 class="text-2xl font-semibold mb-6 text-white">设备连接</h2>
        
        <div class="mb-6">
          <button
            @click="requestDevice"
            :disabled="!isSupported"
            class="tech-button disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-usb mr-2"></i>
            连接 HID 设备
          </button>
        </div>

        <!-- 已连接设备列表 -->
        <div v-if="connectedDevices.length > 0" class="space-y-4">
          <h3 class="text-lg font-semibold text-white">已连接设备</h3>
          <div
            v-for="device in connectedDevices"
            :key="device.device.productId"
            class="bg-gray-800 rounded-lg p-4"
          >
            <div class="flex items-center justify-between mb-3">
              <div>
                <h4 class="text-white font-medium">{{ device.info.productName || '未知设备' }}</h4>
                <p class="text-gray-400 text-sm">
                  厂商: {{ device.info.vendorName || '未知' }} | 
                  产品ID: {{ device.device.productId }} | 
                  厂商ID: {{ device.device.vendorId }}
                </p>
              </div>
              <div class="flex gap-2">
                <button
                  v-if="!device.isOpen"
                  @click="openDevice(device)"
                  class="bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded text-sm transition-colors"
                >
                  打开
                </button>
                <button
                  v-else
                  @click="closeDevice(device)"
                  class="bg-red-600 hover:bg-red-700 text-white px-3 py-1 rounded text-sm transition-colors"
                >
                  关闭
                </button>
                <button
                  @click="removeDevice(device)"
                  class="bg-gray-600 hover:bg-gray-700 text-white px-3 py-1 rounded text-sm transition-colors"
                >
                  移除
                </button>
              </div>
            </div>
            
            <!-- 设备详细信息 -->
            <div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-sm">
              <div>
                <span class="text-gray-400">状态:</span>
                <span :class="device.isOpen ? 'text-green-400' : 'text-gray-400'" class="ml-2">
                  {{ device.isOpen ? '已打开' : '已关闭' }}
                </span>
              </div>
              <div>
                <span class="text-gray-400">集合数量:</span>
                <span class="text-white ml-2">{{ device.device.collections.length }}</span>
              </div>
            </div>

            <!-- 输入数据显示 -->
            <div v-if="device.isOpen && device.inputData.length > 0" class="mt-4">
              <h5 class="text-white font-medium mb-2">最近输入数据:</h5>
              <div class="bg-gray-900 rounded p-3 max-h-32 overflow-y-auto">
                <div
                  v-for="(data, index) in device.inputData.slice(-5)"
                  :key="index"
                  class="text-xs text-gray-300 font-mono mb-1"
                >
                  [{{ data.timestamp }}] {{ data.data }}
                </div>
              </div>
            </div>
          </div>
        </div>

        <div v-else class="text-center text-gray-400 py-8">
          <i class="i-carbon-gamepad text-4xl mb-4 block mx-auto opacity-50"></i>
          <p>暂无连接的设备</p>
          <p class="text-sm mt-2">点击上方按钮连接 HID 设备</p>
        </div>
      </div>

      <!-- 数据发送区域 -->
      <div v-if="openDevices.length > 0" class="tech-card mb-8">
        <h3 class="text-xl font-semibold mb-4 text-white">发送数据</h3>
        
        <div class="space-y-4">
          <div>
            <label class="block text-gray-300 mb-2">选择设备:</label>
            <select
              v-model="selectedDeviceIndex"
              class="w-full bg-gray-800 text-white border border-gray-700 rounded-lg px-3 py-2"
            >
              <option
                v-for="(device, index) in openDevices"
                :key="index"
                :value="index"
              >
                {{ device.info.productName || '未知设备' }}
              </option>
            </select>
          </div>
          
          <div>
            <label class="block text-gray-300 mb-2">数据 (十六进制):</label>
            <input
              v-model="outputData"
              type="text"
              placeholder="例如: 01 02 03 04"
              class="w-full bg-gray-800 text-white border border-gray-700 rounded-lg px-3 py-2"
            >
          </div>
          
          <button
            @click="sendData"
            :disabled="!selectedDevice || !outputData.trim()"
            class="tech-button disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <i class="i-carbon-send mr-2"></i>
            发送数据
          </button>
        </div>
      </div>

      <!-- 错误信息 -->
      <div v-if="error" class="tech-card border-red-600 mb-8">
        <div class="flex items-center mb-2">
          <i class="i-carbon-warning text-red-500 text-xl mr-3"></i>
          <h3 class="text-xl font-semibold text-red-500">错误</h3>
        </div>
        <p class="text-gray-300">{{ error }}</p>
      </div>

      <!-- API 信息 -->
      <div class="tech-card">
        <h3 class="text-xl font-semibold mb-4 text-white">API 信息</h3>
        <div class="space-y-4 text-gray-300">
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">浏览器支持</h4>
            <p>Chrome 89+, Edge 89+ (需要启用实验性功能)</p>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">主要方法</h4>
            <ul class="list-disc list-inside space-y-1">
              <li><code class="bg-gray-800 px-2 py-1 rounded">navigator.hid.requestDevice()</code> - 请求设备访问权限</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">device.open()</code> - 打开设备连接</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">device.sendReport()</code> - 发送数据报告</li>
              <li><code class="bg-gray-800 px-2 py-1 rounded">device.addEventListener('inputreport')</code> - 监听输入数据</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">使用场景</h4>
            <ul class="list-disc list-inside space-y-1">
              <li>游戏手柄和控制器支持</li>
              <li>自定义硬件设备控制</li>
              <li>工业设备监控和控制</li>
              <li>教育和原型开发</li>
            </ul>
          </div>
          <div>
            <h4 class="font-semibold text-tech-accent mb-2">安全限制</h4>
            <ul class="list-disc list-inside space-y-1">
              <li>需要用户手势触发（点击等）</li>
              <li>需要 HTTPS 安全上下文</li>
              <li>某些敏感设备可能被阻止访问</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue'

// 类型定义
interface DeviceInfo {
  productName?: string
  vendorName?: string
}

interface ConnectedDevice {
  device: HIDDevice
  info: DeviceInfo
  isOpen: boolean
  inputData: Array<{ timestamp: string, data: string }>
}

// 响应式状态
const isSupported = ref(false)
const connectedDevices = ref<ConnectedDevice[]>([])
const selectedDeviceIndex = ref(0)
const outputData = ref('')
const error = ref('')

// 计算属性
const openDevices = computed(() => 
  connectedDevices.value.filter(device => device.isOpen)
)

const selectedDevice = computed(() => 
  openDevices.value[selectedDeviceIndex.value]
)

// 检查浏览器支持
onMounted(() => {
  isSupported.value = 'hid' in navigator
  
  if (isSupported.value) {
    // 监听设备连接和断开
    navigator.hid.addEventListener('connect', handleDeviceConnect)
    navigator.hid.addEventListener('disconnect', handleDeviceDisconnect)
  }
})

// 清理事件监听器
onUnmounted(() => {
  if (isSupported.value) {
    navigator.hid.removeEventListener('connect', handleDeviceConnect)
    navigator.hid.removeEventListener('disconnect', handleDeviceDisconnect)
  }
})

// 请求设备访问权限
const requestDevice = async () => {
  try {
    error.value = ''
    
    const devices = await navigator.hid.requestDevice({
      filters: [
        // 游戏手柄
        { usagePage: 0x01, usage: 0x05 },
        // 键盘
        { usagePage: 0x01, usage: 0x06 },
        // 鼠标
        { usagePage: 0x01, usage: 0x02 }
      ]
    })

    for (const device of devices) {
      if (!connectedDevices.value.find(d => d.device === device)) {
        const deviceInfo = await getDeviceInfo(device)
        connectedDevices.value.push({
          device,
          info: deviceInfo,
          isOpen: false,
          inputData: []
        })
      }
    }
  } catch (err) {
    console.error('请求设备失败:', err)
    error.value = err instanceof Error ? err.message : '请求设备失败'
  }
}

// 获取设备信息
const getDeviceInfo = async (device: HIDDevice): Promise<DeviceInfo> => {
  return {
    productName: device.productName,
    vendorName: device.vendorName
  }
}

// 打开设备
const openDevice = async (deviceWrapper: ConnectedDevice) => {
  try {
    error.value = ''
    await deviceWrapper.device.open()
    deviceWrapper.isOpen = true
    
    // 监听输入数据
    deviceWrapper.device.addEventListener('inputreport', (event) => {
      handleInputReport(deviceWrapper, event)
    })
  } catch (err) {
    console.error('打开设备失败:', err)
    error.value = err instanceof Error ? err.message : '打开设备失败'
  }
}

// 关闭设备
const closeDevice = async (deviceWrapper: ConnectedDevice) => {
  try {
    error.value = ''
    await deviceWrapper.device.close()
    deviceWrapper.isOpen = false
  } catch (err) {
    console.error('关闭设备失败:', err)
    error.value = err instanceof Error ? err.message : '关闭设备失败'
  }
}

// 移除设备
const removeDevice = (deviceWrapper: ConnectedDevice) => {
  if (deviceWrapper.isOpen) {
    closeDevice(deviceWrapper)
  }
  const index = connectedDevices.value.indexOf(deviceWrapper)
  if (index > -1) {
    connectedDevices.value.splice(index, 1)
  }
}

// 处理输入报告
const handleInputReport = (deviceWrapper: ConnectedDevice, event: HIDInputReportEvent) => {
  const data = new Uint8Array(event.data.buffer)
  const hexData = Array.from(data)
    .map(byte => byte.toString(16).padStart(2, '0'))
    .join(' ')
  
  deviceWrapper.inputData.push({
    timestamp: new Date().toLocaleTimeString(),
    data: hexData.toUpperCase()
  })
  
  // 只保留最近50条记录
  if (deviceWrapper.inputData.length > 50) {
    deviceWrapper.inputData.splice(0, deviceWrapper.inputData.length - 50)
  }
}

// 发送数据
const sendData = async () => {
  if (!selectedDevice.value || !outputData.value.trim()) return
  
  try {
    error.value = ''
    
    // 解析十六进制数据
    const hexData = outputData.value.trim().split(/\s+/)
    const data = new Uint8Array(hexData.map(hex => parseInt(hex, 16)))
    
    await selectedDevice.value.device.sendReport(0, data)
    
    // 清空输入框
    outputData.value = ''
  } catch (err) {
    console.error('发送数据失败:', err)
    error.value = err instanceof Error ? err.message : '发送数据失败'
  }
}

// 处理设备连接
const handleDeviceConnect = (event: HIDConnectionEvent) => {
  console.log('设备已连接:', event.device)
}

// 处理设备断开
const handleDeviceDisconnect = (event: HIDConnectionEvent) => {
  console.log('设备已断开:', event.device)
  const deviceWrapper = connectedDevices.value.find(d => d.device === event.device)
  if (deviceWrapper) {
    removeDevice(deviceWrapper)
  }
}
</script>
